Show the code
fern_transform <- function(coord, ind) {
# coefficients for the stem function f_1
if(ind == 1) {
mat <- matrix(c(0, 0, 0, .16), 2, 2) # matrix to multiply
off <- c(0, 0) # offset vector to add
}
# coefficients for the small leaflet function f_2
if(ind == 2) {
mat <- matrix(c(.85, -.04, .04, .85), 2, 2)
off <- c(0, 1.6)
}
# coefficients for the right-side function f_3
if(ind == 3) {
mat <- matrix(c(.2, .23, -.26, .22), 2, 2)
off <- c(0, 1.6)
}
# coefficients for the left-side function f_4
if(ind == 4) {
mat <- matrix(c(-.15, .26, .28, .24), 2, 2)
off <- c(0, .44)
}
# return the affine transformed coords
coord <- mat %*% coord + off
return(coord)
}
Show the code
fern_chaos <- function(iterations = 10000, seed = NULL) {
if(!is.null(seed)) set.seed(seed)
# which transformation to apply at each iteration
transform_index <- sample(
x = 1:4,
size = iterations,
replace= TRUE,
prob = c(.01, .85, .07, .07)
)
# initialise chaos game at the origin
start <- matrix(c(0, 0))
# helper function to collapse accumulated output
bind_to_column_matrix <- function(lst) {
do.call(cbind, lst)
}
# iterate until done!
coord_matrix <- transform_index |>
accumulate(fern_transform, .init = start) |>
bind_to_column_matrix()
# tidy the output, add extra columns, and return
coord_df <- t(coord_matrix) |>
as.data.frame()
names(coord_df) <- c("x", "y")
coord_df <- coord_df |>
as_tibble() |>
mutate(
transform = c(0, transform_index),
iteration = row_number() - 1
)
return(coord_df)
}
# A tibble: 6 × 4
x y transform iteration
<dbl> <dbl> <dbl> <dbl>
1 0 0 0 0
2 0 1.6 2 1
3 0.064 2.96 2 2
4 0.173 4.11 2 3
5 -1.03 2.54 3 4
6 -0.778 3.80 2 5
Show the code
ggplot(fern_dat, aes(x, y)) +
geom_point(colour = "yellow", size = 1, stroke = 0) +
coord_equal() +
theme_void()
Show the code
ggplot(fern_dat, aes(x, y, colour = iteration)) +
geom_point(size = 1, stroke = 0, show.legend = FALSE) +
coord_equal() +
theme_void()